#ifndef AVL_TEST_H
#define AVL_TEST_H

#include <vector>
#include <utility>
#include <string>
#include <array>
#include <iostream>
#include <fstream>

#include <nlohmann/json.hpp>

#include "avl.h"

enum avl_op_tp {
    AVL_INSERT = 0,
    AVL_DEL,
    AVL_FIND,
    AVL_NULL_OP
};

struct avl_cont_op {

    bool operator==(const avl_cont_op &op1) const{
        return tp == op1.tp && cnt == op1.cnt;
    }

    avl_op_tp tp{AVL_NULL_OP};
    uint32_t cnt{};
};

struct avl_test_case {

    avl_test_case() = default;

    avl_test_case(std::vector<int> &&v, 
                            std::vector< avl_cont_op > &&ops, 
                            std::vector<int> &&last_order_seqs):
                            input{std::move(v)},op{std::move(ops)},expect_seq{std::move(last_order_seqs)}
    {

    }

    avl_test_case(const  std::vector<int> &v, 
                 const std::vector<avl_cont_op> &ops,
                const  std::vector<int> &expect): input{v}, op{ops},expect_seq{expect}
    {

    }

    bool isEqual(const avl_test_case &tcase) {
        return tcase.expect_seq == expect_seq && tcase.input == input && tcase.op == op;
    }

    std::vector<int> input{};
    std::vector< avl_cont_op > op{};
    std::vector<int> expect_seq{};

  
};


struct avl_test_suite {

    std::string suite_name; 
    std::vector<avl_test_case> cases{};    
};


namespace nlohmann {
    template<>
    struct adl_serializer<avl_cont_op> {
        static void to_json(json& j, const avl_cont_op& cont_op) {
            j = json::object();
            j["tp"] = cont_op.tp;
            j["cnt"] = cont_op.cnt;
        }
        
        static void from_json(const json& j, avl_cont_op& cont_op) {
            j.at("tp").get_to(cont_op.tp);
            j.at("cnt").get_to(cont_op.cnt);
        }
    };
}


// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(avl_cont_op, tp, cnt)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(avl_test_case, input, op, expect_seq)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(avl_test_suite, suite_name, cases)





class AVLTestRunner {
public:
    static bool run_test_case(const avl_test_case& test_case);
    static void run_test_suite(const avl_test_suite& test_suite);
};


class AVLTestManager{
public:

    explicit AVLTestManager(const std::string &filename):filename_{filename}
    {
        load_data();
    }

    bool addTestCase(const std::string &suite_name, const avl_test_case& test_case);
    bool removeTestSuite(const std::string &suite_name);
    bool removeTestCase(const std::string &suite_name, const avl_test_case& test_case);
    

    bool removeTestCaseByIndex(const std::string &suite_name, size_t idx);


    std::vector<avl_test_suite> getAllTestSuites();

private:
    void load_data();
    void save_data();


    nlohmann::json data_;
    std::string filename_;
};

#endif